/* Woodstox Lite ("wool") XML processor
 *
 * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi
 *
 * Licensed under the License specified in the file LICENSE which is
 * included with the source code.
 * You may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.fasterxml.aalto.in;

/**
 * Simple factory that can instantiate appropriate {@link PName}
 * instances, given input data to use for construction. The main reason
 * for a factory class here is just to insulate calling code from having
 * to know details of concrete implementations.
 */
public final class ByteBasedPNameFactory
{
    /**
     * Can be set to false for debugging (for example, to test memory
     * usage)
     */
    private final static boolean DO_INTERN = true;
    //private final static boolean DO_INTERN = false;

    /*
    //////////////////////////////////////////////////////////
    // Life-cycle
    //////////////////////////////////////////////////////////
     */

    private final static ByteBasedPNameFactory sInstance = new ByteBasedPNameFactory();

    private ByteBasedPNameFactory() { }

    public static ByteBasedPNameFactory getInstance() { return sInstance; }

    /*
    //////////////////////////////////////////////////////////
    // Public API
    //////////////////////////////////////////////////////////
     */

    public ByteBasedPName constructPName(int hash, String pname, int colonIx,
                                         int quad1, int quad2)
    {
        if (colonIx < 0) { // no prefix, simpler
            String ln = pname;
            if (DO_INTERN) {
                ln = ln.intern();
            }
            if (quad2 == 0) { // one quad only?
                return new PName1(ln, null, ln, hash, quad1);
            }
            return new PName2(ln, null, ln, hash, quad1, quad2);
        }
        /* !!! TODO: cache prefix intern() calls, since they are bound
         * to cluster nicely (and quite often within same thread too)
         */
        String prefix = pname.substring(0, colonIx);
        String ln = pname.substring(colonIx+1);
        if (DO_INTERN) {
            prefix = prefix.intern();
            ln = ln.intern();
        }

        if (quad2 == 0) { // one quad only?
            return new PName1(pname, prefix, ln, hash, quad1);
        }
        return new PName2(pname, prefix, ln, hash, quad1, quad2);
    }

    public ByteBasedPName constructPName(int hash, String pname, int colonIx,
                                         int[] quads, int qlen)
    {
        if (qlen < 4) { // Need to check for 3 quad one, can do others too
            if (colonIx < 0) { // no prefix
                if (DO_INTERN) {
                    pname = pname.intern();
                }
                if (qlen == 3) {
                    return new PName3(pname, null, pname, hash, quads);
                } else if (qlen == 2) {
                    return new PName2(pname, null, pname, hash, quads[0], quads[1]);
                }
                return new PName1(pname, null, pname, hash, quads[0]);
            }
            String prefix = pname.substring(0, colonIx);
            String ln = pname.substring(colonIx+1);
            if (DO_INTERN) {
                ln = ln.intern();
                prefix = prefix.intern();
            }
            if (qlen == 3) {
                return new PName3(pname, prefix, ln, hash, quads);
            } else if (qlen == 2) {
                return new PName2(pname, prefix, ln, hash, quads[0], quads[1]);
            }
            return new PName1(pname, prefix, ln, hash, quads[0]);
        }
        // But also need to copy the incoming int buffer:
        int[] buf = new int[qlen];
        for (int i = 0; i < qlen; ++i) {
            buf[i] = quads[i];
        }
        if (colonIx < 0) { // no prefix, simpler
            if (DO_INTERN) {
                pname = pname.intern();
            }
            return new PNameN(pname, null, pname, hash, buf, qlen);
        }
        /* !!! TODO: cache prefix intern() calls, since they are bound
         * to cluster nicely (and quite often within same thread too)
         */
        String prefix = pname.substring(0, colonIx);
        String ln = pname.substring(colonIx+1);
        if (DO_INTERN) {
            ln = ln.intern();
            prefix = prefix.intern();
        }
        return new PNameN(pname, prefix, ln, hash, buf, qlen);
    }
}
